﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using UpdateBot2.FileHippo;
using System.Threading.Tasks;
using Microsoft.Win32;
using System.Threading;
using System.Net;
using System.ComponentModel;
using UpdateBot2.DownloadSource;

namespace UpdateBot2.UI
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        private ObservableCollection<FileHippoDataGridItem> HippoData = new ObservableCollection<FileHippoDataGridItem>();
        public String StartUpURL { get; set; }

        public enum WindowStatus
        {
            Loading, Idle, Downloading
        }

        /// <summary>
        /// 
        /// </summary>
        public long DownloadRate
        {
            set
            {
                this.DownloadRateLabel.Text = String.Format("{0}/s", DownloadServer.BytesToString(value));
                this.DownloadRateLabel.Visibility = (value <= 0) ? Visibility.Hidden : Visibility.Visible;
            }
        }

        /// <summary>
        /// Represents the Status TextBlock in the status bar.
        /// </summary>
        public String StatusMessage
        {
            get
            {
                return this.StatusLabel.Text;
            }
            set
            {
                this.StatusLabel.Text = value;
                this.StatusLabel.Visibility = (String.IsNullOrWhiteSpace(value)) ? Visibility.Hidden : Visibility.Visible;
            }
        }

        public MainWindow()
        {
            InitializeComponent();
            StartUpURL = String.Empty;
            this.downloadsGrid.ItemsSource = HippoData;
        }

        /// <summary>
        /// Displays the "Loading Download Information" popup.
        /// </summary>
        /// <param name="show"></param>
        public void ShowPendingProgress(Boolean show)
        {
            progressCanvas.Visibility = (show) ? System.Windows.Visibility.Visible : System.Windows.Visibility.Hidden;
        }

        /// <summary>
        /// Checks or unchecks each download on input.
        /// </summary>
        /// <param name="b"></param>
        public void ToggleDownloadCheckStatus(Boolean b)
        {
            foreach (FileHippoDataGridItem item in HippoData)
            {
                item.IsChecked = b;
            }
        }

        public void SetWindowStatus(WindowStatus state)
        {
            switch (state)
            {
                case WindowStatus.Loading:
                    ShowPendingProgress(true);
                    StartDownloadButton.IsEnabled = false;
                    StatusMessage = "Loading...";
                    break;
                case WindowStatus.Downloading:
                    ShowPendingProgress(false);
                    StartDownloadButton.IsEnabled = false;
                    StatusMessage = "Downloading...";
                    break;
                case WindowStatus.Idle:
                    ShowPendingProgress(false);
                    StartDownloadButton.IsEnabled = true;
                    StatusMessage = "Idle";
                    break;
            }
        }

        public void LoadUpdateCheckerPage(String url)
        {
            Uri pageURI = null;

            //Prove its a proper URI and from update.filehippo.com domain.
            if (Uri.IsWellFormedUriString(url, UriKind.Absolute) && (pageURI = new Uri(url)).Host.ToLower().Equals("update.filehippo.com"))
            {
                SetWindowStatus(WindowStatus.Loading);
                Task downloadTask = Task.Factory.StartNew(() =>
                {
                    //Scan initial update list and get ID's.
                    FileHippoServer server = new FileHippoServer(Properties.Settings.Default.NoBetaPrograms, Properties.Settings.Default.NoDemoPrograms);
                    List<DownloadSource.DownloadResourceIdentifier> dat = null;

                    try
                    {
                        dat = server.ParseUpdateCheckerPage(pageURI);
                    }
                    catch (System.Net.WebException fourOfour)
                    {
                        Dispatcher.BeginInvoke(new Action(delegate
                        {
                            SetWindowStatus(WindowStatus.Idle);
                            MessageBox.Show(fourOfour.Message, "Error Reaching WebPage", MessageBoxButton.OK, MessageBoxImage.Error);
                        }));
                        return;
                    }

                    foreach (DownloadSource.DownloadResourceIdentifier downloadID in dat)
                    {
                        FileHippoDownload down = server.GetDownloadTarget(downloadID) as FileHippoDownload;

                        //Add each one as it appears.
                        Dispatcher.BeginInvoke(new Action(delegate
                        {
                            HippoData.Add(new FileHippoDataGridItem(down));
                        }));

                    }

                    //Set window back to idle mode awaiting further actions...
                    Dispatcher.BeginInvoke(new Action(delegate
                    {
                        SetWindowStatus(WindowStatus.Idle);
                    }));

                });
            }
            else
            {
                MessageBox.Show("The specified URL is not a valid FileHippo.com location!", "Invalid URL", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// This places the Loading Downloads status in the center of the application's DataGrid.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            double left = (progressCanvas.ActualWidth - loadingPanel.ActualWidth) / 2;
            Canvas.SetLeft(loadingPanel, left);

            double top = (progressCanvas.ActualHeight - loadingPanel.ActualHeight) / 2;
            Canvas.SetTop(loadingPanel, top);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
            dialog.ShowNewFolderButton = true;
            dialog.RootFolder = Environment.SpecialFolder.UserProfile;

            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {

                Task downloadAllTask = Task.Factory.StartNew(() =>
                {
                    FileHippoServer server = new FileHippoServer(Properties.Settings.Default.NoBetaPrograms, Properties.Settings.Default.NoDemoPrograms);
                    AutoResetEvent autozone = new AutoResetEvent(false);

                    //Setup event listeners!
                    DateTime previousSpeedReport = DateTime.Now;

                    server.HippoClient.DownloadProgressChanged += delegate(object hippoSender, DownloadProgressChangedEventArgs downloadEvent)
                    {
                        FileHippoDataGridItem targetDownload = downloadEvent.UserState as FileHippoDataGridItem;
                        targetDownload.DownloadProgress = downloadEvent.ProgressPercentage;

                        /*
                         *TODO: Fix proper download rate!
                        DateTime now = DateTime.Now;
                        TimeSpan sinceLastReport = now - previousSpeedReport;

                        long speed = 0;
                        
                        //Check for any distance; we want to do it every second AND avoid divide by 0.
                        if (sinceLastReport.TotalSeconds >= 1)
                        {
                            speed = downloadEvent.BytesReceived / (long)sinceLastReport.TotalSeconds;
                            previousSpeedReport = now;
                        }
                        */

                        Dispatcher.BeginInvoke(new Action(delegate
                        {
                            StatusMessage = String.Format("Downloading... {0}%", downloadEvent.ProgressPercentage);
                            //DownloadRate = speed;
                        }));
                    };

                    server.HippoClient.DownloadFileCompleted += delegate(object downloadCompleteSender, AsyncCompletedEventArgs downloadCompleteEvent)
                    {
                        autozone.Set();
                    };

                    foreach (FileHippoDataGridItem dItem in HippoData)
                    {
                        if (dItem.IsChecked)
                        {
                            dItem.WhenStarted = DateTime.Now;   //Set the start time.
                            server.DownloadTargetAsync(dItem, new System.IO.DirectoryInfo(dialog.SelectedPath));
                            autozone.Reset();

                            autozone.WaitOne();
                        }
                    }

                    autozone.Close();
                    Dispatcher.BeginInvoke(new Action(delegate
                    {
                        SetWindowStatus(WindowStatus.Idle);
                        MessageBox.Show("All selected downloads are complete!");
                    }));
                });
            }
        }

        private void ScanUpdatePageButton_Click(object sender, RoutedEventArgs e)
        {
            InputWindow prompt = new InputWindow("New Page", "Scan Page", String.Empty, "Add Update Checker Page");
            prompt.Owner = this; //Make sure it positions correctly!

            bool? r = prompt.ShowDialog();

            if (r.HasValue && r.Value)
            {
                LoadUpdateCheckerPage(prompt.Text);
            }
        }

        /// <summary>
        /// Called before window is shown.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            if (!String.IsNullOrEmpty(this.StartUpURL))
            {
                SetWindowStatus(WindowStatus.Loading);
                LoadUpdateCheckerPage(this.StartUpURL);
            }
        }

        private void CheckAllButton_Click(object sender, RoutedEventArgs e)
        {
            ToggleDownloadCheckStatus(true);
        }

        private void UnCheckAllButton_Click(object sender, RoutedEventArgs e)
        {
            ToggleDownloadCheckStatus(false);
        }
    }
}
